package com.example.yx1.demo42;

import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Configuration
public class A42_2 {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A42_2.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();


        //1.测试数组解析
        System.out.println("1.测试数组解析");
        testArray(beanFactory);

        //2.测试List解析
        System.out.println("2.测试List解析");
        testList(beanFactory);

        //3.测试ApplicationContext解析
        System.out.println("3.测试ApplicationContext解析");
        testApplicationContext(beanFactory);

        //4.测试Generic解析
        System.out.println("4.测试Generic解析");
        testGeneric(beanFactory);

        //5.测试Qualifier解析
        System.out.println("5.测试Qualifier解析");
        testQualifier(beanFactory);

    }

    private static void testQualifier(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        // 取得类型的描述信息
        DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);

        // 获取该类型
        Class<?> dependencyType = dd5.getDependencyType();
        // 得到一个上下文中注解有关自动注入的候选解析器
        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);

        //遍历容器中所有符合这个类型的Bean的名字
        for (String names : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType)) {
            // 取得这些 Bean的定义，这个定义包含了泛型参数
            BeanDefinition bd = beanFactory.getMergedBeanDefinition(names);
            // 如果这个候选器能将这个bean定义以及名字和描述信息进行匹配：isAutowireCandidate ：是否是它的候选器，是的话就返回
            if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,names),dd5)) {
                System.out.println(names);
                System.out.println(dd5.resolveCandidate(names,dependencyType,beanFactory));
            }
        }
    }

    private static void testGeneric(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        // 取得类型的描述信息
        DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);

        // 获取该类型
        Class<?> dependencyType = dd4.getDependencyType();
        // 得到一个上下文中注解有关自动注入的候选解析器
        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);

        //遍历容器中所有符合这个类型的Bean的名字
        for (String names : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType)) {
            // 取得这些 Bean的定义，这个定义包含了泛型参数
            BeanDefinition bd = beanFactory.getMergedBeanDefinition(names);
            // 如果这个候选器能将这个bean定义以及名字和描述信息进行匹配：isAutowireCandidate ：是否是它的候选器，是的话就返回
            if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,names),dd4)) {
                System.out.println(names);
                System.out.println(dd4.resolveCandidate(names,dependencyType,beanFactory));
            }
        }
    }

    private static void testApplicationContext(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException,IllegalAccessException {
        // 取得 这个 ConfigurableApplicationContext 类型的描述信息
        DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);

        // 反射调用 从而拿到 那个存放特殊类型的集合
        Field resolvableDependencies = DefaultListableBeanFactory.class.getDeclaredField("resolvableDependencies");
        resolvableDependencies.setAccessible(true);
        Map<Class<?> ,Object> dependencies = (Map<Class<?>, Object>) resolvableDependencies.get(beanFactory);

        // 遍历集合，判断我的类型是否是里面类型的子类
        for (Map.Entry<Class<?>,Object> entry : dependencies.entrySet()) {
            // 判断 注入的类型能否转换成map里已有的类型
            //左边类型                          右边类型
            if (entry.getKey().isAssignableFrom(dd3.getDependencyType())) {
                System.out.println(entry.getValue());
                break;
            }
        }
    }

    private static void testList(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        // 首先取到这个属性
        DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);
        // 如果这个属性是集合类型
        if (dd2.getDependencyType() == List.class) {
            // 得到该集合的元素类型
            Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();
            System.out.println(resolve);
            // 用于存放的 List 集合
            List<Object> list = new ArrayList<>();
            // 工具类，用于查找当前容器以及祖先容器所有符合这个类型的Bean的名字
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);
            for (String name : names) {
                Object bean = dd2.resolveCandidate(name,resolve,beanFactory);
                list.add(bean);
            }
            // 由于本身是集合类型，原样返回即可
            System.out.println(list);
        }

    }

    private static void testArray(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        // 首先取到这个属性
        DependencyDescriptor dd1 = new DependencyDescriptor(Target.class.getDeclaredField("serviceArray"), true);
        // 如果这个属性是数组类型
        if (dd1.getDependencyType().isArray()) {
            // 得到该数组的元素类型
            Class<?> type = dd1.getDependencyType().getComponentType();
            System.out.println(type);
            // 用于存放的 List 集合
            List<Object> beans = new ArrayList<>();
            // 工具类，用于查找当前容器以及祖先容器所有符合这个类型的Bean的名字
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,type);
            // 遍历，然后加入集合中
            for (String name : names) {
                System.out.println(name);
                Object bean = dd1.resolveCandidate(name, type, beanFactory);
                beans.add(bean);
            }
            // 通过类型转换，将结果封装成数组返回
            Object result = beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
            System.out.println(result);
        }
    }

    static class Target {
        @Autowired private Service[] serviceArray;
        @Autowired private List<Service> serviceList;
        @Autowired private ConfigurableApplicationContext applicationContext;
        @Autowired private Dao<Teacher> dao;
        @Autowired @Qualifier("service2") private Service service;

    }


    interface Service{}

    @Component("service1")
    static class Service1 implements Service{}

    @Component("service2")
    @Primary
    static class Service2 implements Service{}

    @Component("service3")
    static class Service3 implements Service{}

    interface Dao<T>{}

    static class Student{}

    static class Teacher{}

    @Component("dao1")
    static class Dao1 implements Dao<Student>{}

    @Component("dao2")
    static class Dao2 implements Dao<Teacher>{}


}
